package com.open.capacity.reptile.util;

import com.open.capacity.reptile.dto.common.ResponseWithCookies;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.*;

/**
 * http 工具类 获取请求中的参数
 *
 * @author show
 * @date 14:23 2019/5/29
 */
@Slf4j
public class HttpUtils {

    public static String requestGet(String remoteUrlStr) {
        String msg = "";
        HttpURLConnection connection = null;
        try {
            // 1. 得到访问地址的URL
            URL url = new URL(remoteUrlStr);
            // 2. 得到网络访问对象java.net.HttpURLConnection
            connection = (HttpURLConnection) url.openConnection();
            /* 3. 设置请求参数（过期时间，输入、输出流、访问方式），以流的形式进行连接 */
            // 设置是否向HttpURLConnection输出
            connection.setDoOutput(false);
            // 设置是否从HttpUrlConnection读入
            connection.setDoInput(true);
            // 设置请求方式
            connection.setRequestMethod("GET");
            // 设置是否使用缓存
            connection.setUseCaches(true);
            // 设置此 HttpURLConnection 实例是否应该自动执行 HTTP 重定向
            connection.setInstanceFollowRedirects(true);
            // 设置超时时间
            connection.setConnectTimeout(3000);
            // 连接
            connection.connect();
            // 4. 得到响应状态码的返回值 responseCode
            int code = connection.getResponseCode();
            // 5. 如果返回值正常，数据在网络中是以流的形式得到服务端返回的数据

            if (code == 200) { // 正常响应
                // 从流中读取响应信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循环从流中读取
                    msg += line + "\n";
                }
                reader.close(); // 关闭流
            }
            // 显示响应结果
//            System.out.println(msg);
            if ("{\"msg\":\"验证码错误或已失效，请刷新或者重试\",\"code\":\"-1\"}".equals(msg)) {
                return requestGet(remoteUrlStr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6. 断开连接，释放资源
            try {
                connection.disconnect();
            } catch (Exception e) {
            }
        }
        return msg;
    }

    public static ResponseWithCookies requestForPost(String url, Map<String, String> params, List<Cookie> cookieList, Header[] headerList) throws IOException {
        String content = "";
        ResponseWithCookies response = new ResponseWithCookies();
        /** 创建HttpClient */
        BasicCookieStore cookieStore = new BasicCookieStore();
        if (CollectionUtils.isNotEmpty(cookieList)) {
            for (Cookie item : cookieList) {
                cookieStore.addCookie(item);
            }
        }

        /** 创建HttpClient */
        CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();

        /** httpPost */
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> paramsList = new ArrayList<>();
        Iterator<Map.Entry<String, String>> it = params.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            String key = en.getKey();
            String value = en.getValue();
            paramsList.add(new BasicNameValuePair(key, value));
        }
        httpPost.setEntity(new UrlEncodedFormEntity(paramsList, "UTF-8"));
        if (headerList != null && headerList.length > 0) {
            httpPost.setHeaders(headerList);
        }
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try {
            HttpEntity httpEntity = httpResponse.getEntity();
            content = EntityUtils.toString(httpEntity, "UTF-8");
            response.setContent(content);
            EntityUtils.consume(httpEntity);

            //cooikes
            List<Cookie> cookies = cookieStore.getCookies();
            response.setCookies(cookies);
        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException e) {
                log.info("## release resouce error ##" + e);
            }
        }
        return response;
    }

    public static ResponseWithCookies requestForPost(String url, Map<String, String> params, List<Cookie> cookieList) throws IOException {
        return requestForPost(url, params, cookieList, null);
    }

    public static String requestForJson(String url, String jsonStr, Header[] headerList) throws IOException {
        String content = "";
        /** 创建HttpClient */

        /** 创建HttpClient */
        CloseableHttpClient httpClient = HttpClients.custom().setRetryHandler(retryHandler()).build();

        /** httpPost */
        HttpPost httpPost = new HttpPost(url);

        if (headerList != null && headerList.length > 0) {
            httpPost.setHeaders(headerList);
        } else {
            httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
        }
        if (null != jsonStr) {
            StringEntity entity = new StringEntity(jsonStr);
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
        }

        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try {
            HttpEntity httpEntity = httpResponse.getEntity();
            content = EntityUtils.toString(httpEntity, "UTF-8");
            EntityUtils.consume(httpEntity);
        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException e) {
                log.info("## release resouce error ##" + e);
            }
        }
        return content;
    }

    public static ResponseWithCookies requestForJson(String url, String jsonStr, List<Cookie> cookieList) throws IOException {
        String content = "";
        ResponseWithCookies response = new ResponseWithCookies();
        /** 创建HttpClient */
        BasicCookieStore cookieStore = new BasicCookieStore();
        if (CollectionUtils.isNotEmpty(cookieList)) {
            for (Cookie item : cookieList) {
                cookieStore.addCookie(item);
            }
        }

        /** 创建HttpClient */
        CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();

        /** httpPost */
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");

        if (null != jsonStr) {
            StringEntity entity = new StringEntity(jsonStr);
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
        }

        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try {
            HttpEntity httpEntity = httpResponse.getEntity();
            content = EntityUtils.toString(httpEntity, "UTF-8");
            response.setContent(content);
            EntityUtils.consume(httpEntity);

            //cooikes
            List<Cookie> cookies = cookieStore.getCookies();
            response.setCookies(cookies);

        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException e) {
                log.info("## release resouce error ##" + e);
            }
        }
        return response;
    }

    public static ResponseWithCookies requestForGet(String url, List<Cookie> cookieList) throws IOException {
        String content = "";
        ResponseWithCookies response = new ResponseWithCookies();
        BasicCookieStore cookieStore = new BasicCookieStore();
        if (CollectionUtils.isNotEmpty(cookieList)) {
            for (Cookie item : cookieList) {
                cookieStore.addCookie(item);
            }
        }

        /** 创建HttpClient */
        CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();

        /** httpPost */
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
        try {
            HttpEntity httpEntity = httpResponse.getEntity();
            content = EntityUtils.toString(httpEntity, "UTF-8");
            response.setContent(content);
            EntityUtils.consume(httpEntity);

            //cooikes
            List<Cookie> cookies = cookieStore.getCookies();
            response.setCookies(cookies);

        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException e) {
                log.info("## release resouce error ##" + e);
            }
        }
        return response;
    }

    private static HttpRequestRetryHandler retryHandler() {
        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException e, int retryTimes, HttpContext httpContext) {
                if (retryTimes > 2) {
                    return false;
                }
                if (e instanceof UnknownHostException || e instanceof ConnectTimeoutException || !(e instanceof SSLException || e instanceof NoHttpResponseException)) {
                    return true;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(httpContext);
                HttpRequest request = clientContext.getRequest();
                boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                if (idempotent) {
                    return true;
                }
                return true;
            }
        };
        return httpRequestRetryHandler;
    }

    /**
     * 下载远程文件到本地
     *
     * @param url
     * @param localFilePath
     * @return
     */
    public static int downloadFileFromUrl(String url, String localFilePath) {
        try {
            URL httpUrl = new URL(url);
            File f = new File(localFilePath);
            FileUtils.copyURLToFile(httpUrl, f);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
        return 1;
    }

    public static String getCookieValue(List<Cookie> cookies, String name) {
        Optional<Cookie> first = cookies.stream().filter(t -> t.getName().equals(name)).findFirst();
        return first.isPresent() ? first.get().getValue() : null;
    }
}